package com.xyzwps.server.paimon.app

import com.xyzwps.server.paimon.app.dto.LoginInput
import com.xyzwps.server.paimon.app.dto.LoginSendVcodeInput
import com.xyzwps.server.paimon.app.dto.Me
import com.xyzwps.server.paimon.error.Errors
import com.xyzwps.server.paimon.infra.service.SmsService
import com.xyzwps.server.paimon.value.VcodeScene
import com.xyzwps.server.paimon.model.repository.UserRepository
import com.xyzwps.server.paimon.model.service.PhoneVcodeService
import com.xyzwps.server.paimon.model.service.UserSessionDomainService
import org.jetbrains.exposed.v1.jdbc.transactions.transaction
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Service
class LoginAppService(
    private val userRepository: UserRepository,
    private val phoneVcodeService: PhoneVcodeService,
    private val smsService: SmsService,
    private val sessionService: UserSessionDomainService
) {

    @Transactional
    fun sendVcode(input: LoginSendVcodeInput): String = transaction {
        val phone = input.phone
        userRepository.findByPhone(phone)
            ?: // If the user does not exist, return a dkey to pretend the user exists,
            // preventing this interface from being used to test whether the user is
            // registered.
            return@transaction phoneVcodeService.dkey()

        val vcode = phoneVcodeService.generate(phone, VcodeScene.LOGIN)
        smsService.asyncSendLoginVcode(phone, vcode.vcode)
        return@transaction vcode.dkey
    }

    @Transactional
    fun login(input: LoginInput): Me = transaction {
        phoneVcodeService.validate(input.phone, input.vcode, input.dkey, VcodeScene.LOGIN)
        val user = userRepository.findByPhone(input.phone) ?: throw Errors.USER_NOT_FOUND.toEx()
        val session = sessionService.createSession(user)
        return@transaction Me(user, session.token)
    }
}
